package info.nixbear.tgcms.services.dao.appengine;

import info.nixbear.tgcms.domain.EntityBase;
import info.nixbear.tgcms.domain.Website;
import info.nixbear.tgcms.services.dao.DaoException;
import info.nixbear.tgcms.services.dao.EntityDao;
import info.nixbear.tgcms.services.dao.PMF;

import java.util.List;

import javax.jdo.PersistenceManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Transaction;

public class AppengineEntityDao<T extends EntityBase> implements EntityDao<T> {

	Logger logger = LoggerFactory.getLogger(AppengineEntityDao.class);
	private final Class<T> clazz;

	public AppengineEntityDao(Class<T> clazz) {
		this.clazz = clazz;
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<T> listAll() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		List<T> list = (List<T>) pm.newQuery(clazz).execute();
		list = (List<T>) pm.detachCopyAll(list);
		pm.close();
		return list;
	}

	@Override
	public T get(Long id) throws DaoException {
		Website website = new AppengineWebsiteDao().getDefaultWebsite();
		Key key = KeyFactory.createKey(website.getKey(), clazz.getSimpleName(), id);

		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.getFetchPlan().addGroup("all");
		pm.setDetachAllOnCommit(true);

		T entity = null;
		try {
			entity = pm.getObjectById(clazz, key);
			entity = pm.detachCopy(entity);
		} catch (Exception e) {
			logger.error(
					"Entity " + clazz.getSimpleName() + " with id" + id + ", key " + key
							+ " not fount on the website " + website.getName() + ", id: "
							+ website.getId(), e);
		} finally {
			pm.close();
		}
		return entity;
	}

	@Override
	public T get(String key) {
		return null;
	}

	@Override
	public T put(T entity) throws DaoException {
		if (!(entity instanceof Website) && entity.getWebsite() == null) {
			// throw new
			// DaoException("All entities except websites should have a website parent");
			entity.setWebsite(new AppengineWebsiteDao().getDefaultWebsite());
		}
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Transaction txn = datastore.beginTransaction();
		T persistent = null;
		try {
			if (entity.getKey() == null) {
				Key websiteKey = (entity.getWebsite() != null) ? entity.getWebsite().getKey()
						: null;
				Key entityKey = datastore
						.allocateIds(websiteKey, entity.getClass().getSimpleName(), 1).iterator()
						.next();
				entity.setKey(entityKey);
				logger.debug("Allocated key {}", entityKey.toString());
			}
			persistent = pm.makePersistent(entity);
			txn.commit();
			logger.debug("Persisted {}, key: {}", entity.getClass().getSimpleName(), entity
					.getKey().toString());
		} catch (Exception e) {
			logger.error(
					"Not persisted " + entity.getClass().getSimpleName() + " key: "
							+ entity.getKey(), e);
		} finally {
			if (txn.isActive()) {
				txn.rollback();
			}
			pm.close();
		}
		return persistent;
	}

	@Override
	public void delete(T entity) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.deletePersistent(entity);
		pm.close();
	}

	
	public void prepare(EntityBase entity) throws DaoException {
		if (!(entity instanceof Website) && entity.getWebsite() == null) {
			// throw new
			// DaoException("All entities except websites should have a website parent");
			entity.setWebsite(new AppengineWebsiteDao().getDefaultWebsite());
		}
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		if (entity.getKey() == null) {
			Key websiteKey = (entity.getWebsite() != null) ? entity.getWebsite().getKey()
					: null;
			Key entityKey = datastore
					.allocateIds(websiteKey, entity.getClass().getSimpleName(), 1).iterator()
					.next();
			entity.setKey(entityKey);
			logger.debug("Allocated key {}", entityKey.toString());
		}
	}
	
}
